﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Text;
using System.Text.RegularExpressions;
using System.Web.Security;
using System.Web.Configuration;
using WebUI.SmartDatingRef;
using SvcUtils;

namespace WebUI {
    public partial class _Default : BasePage {
        protected global::System.Web.UI.HtmlControls.HtmlInputButton cmdRegister;
        protected global::WebControlCaptcha.CaptchaControl ccJoin;
        protected global::System.Web.UI.HtmlControls.HtmlInputButton cmdLogin;
        
        const int MIN_PASSWORD_LENGTH = 5;

        public override void Dispose() {
            Client.Close();
            base.Dispose();
        }

        private OperationStatus tryKeyEx(string email, string sessionKey) {
            // обмен ключами
            byte[] keyExchange = CryptoImpl.rsaForKeyExchange(b(sessionKey));
            return Client.KeyExchange(email, s(keyExchange));
        }

        private OperationStatus tryAuth(string email, string password, string sessionKey, string sessionKeyHash) {
            // обмен ключами для авторизации
            OperationStatus kexStatus = tryKeyEx(email, sessionKey);
            if (!Status.SUCCESS(kexStatus)) {
                return kexStatus;
            }

            // авторизация
            return Client.Authenticate(sessionKeyHash,
                s( CryptoImpl.cryptAes(Encoding.Unicode.GetBytes(password), b(sessionKey))) );
        }

        private OperationStatus tryRegister(string email, string password) {
            // временный ключ сеанса (только для регистрации)
            byte[] sessionKey = CryptoImpl.getSessionKey();
            byte[] sessionKeyHash = CryptoImpl.sha1(sessionKey);

            // обмен временными ключами
            OperationStatus kexStatus = tryKeyEx("*", s(sessionKey));
            if (!Status.SUCCESS(kexStatus)) {
                return kexStatus;
            }

            // регистрация
            return Client.Register(s(sessionKeyHash), email,
                s( CryptoImpl.cryptAes(Encoding.Unicode.GetBytes(password), sessionKey)) );
        }

        protected void cmdLogin_ServerClick(object sender, EventArgs e) {
            string password = txtPassword.Value;

            string email = HttpUtility.HtmlEncode(txtEmailWho.Value) + "@" +
                HttpUtility.HtmlEncode(txtEmailRealm.Value);
            if (!checkMail(email)) {
                // неверная почта
                Utils.showError(errLoginSpan, "Введен неверный адрес электронной почты.");
                return;
            }

            if (password.Length < MIN_PASSWORD_LENGTH) {
                // слишком короткий пароль
                Utils.showError(errLoginSpan, "Пароль слишком короткий. <br />" +
                          "Допустимы пароли длиной " + MIN_PASSWORD_LENGTH + " и выше.");
                return;
            }

            Utils.hideError(errLoginSpan);

            authSequence(email, password);
        }

        private void authSequence(string email, string password) {
            // ключ сеанса
            byte[] sessionKey = CryptoImpl.getSessionKey();
            byte[] sessionKeyHash = CryptoImpl.sha1(sessionKey);

            OperationStatus authResult = tryAuth(email, password,
                s(sessionKey), s(sessionKeyHash));
            if (!Status.SUCCESS(authResult)) {
                Utils.showError(errLoginSpan, Status.m(authResult));
                return;
            }

            // аутентификация прошла успешно
            SessionKey = s(sessionKey);
            SessionKeyHash = s(sessionKeyHash);

            // пометим это в FormsAuthentication и плавно перейдем на
            // запрошенную страницу (а если ее нет --- на главную страницу юзера)
            FormsAuthentication.SetAuthCookie(email, false);
            if (Request.QueryString["ReturnUrl"] != null) {
                FormsAuthentication.RedirectFromLoginPage(email, false);
            } else {
                Response.Redirect("Dashboard.aspx");
            }
        }

        private bool checkMail(string email) {
            Regex regex = new Regex(@"^([0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*@([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,9})$");
            return email.Length > 1 && email.Length <= 256 && regex.Match(email).Success;
        }

        protected void cmdRegister_ServerClick(object sender, EventArgs e) {
            string email = HttpUtility.HtmlEncode(txtEmailNewWho.Value) + "@" +
                HttpUtility.HtmlEncode(txtEmailNewRealm.Value);
            string password = txtPasswordNew.Value;

            if (!checkMail(email)) {
                // неверная почта
                Utils.showError(errSpan, "Введен неверный адрес электронной почты.");
                return;
            }

            if (password.Length < MIN_PASSWORD_LENGTH) {
                // слишком короткий пароль
                Utils.showError(errSpan, "Пароль слишком короткий. <br />" +
                          "Допустимы пароли длиной " + MIN_PASSWORD_LENGTH + " и выше.");
                return;
            }

            ccJoin.Validate();
            if (!ccJoin.IsValid) {
                // неверная капча
                Utils.showError(errSpan, "Введены неверные цифры с картинки.");
                return;
            }

            Utils.hideError(errSpan);

            // попытка регистрации
            OperationStatus regStatus = tryRegister(email, password);
            if (!Status.SUCCESS(regStatus)) {
                Utils.showError(errSpan, Status.m(regStatus));
                return;
            }

            // после успешной регистрации --- попытка аутентификации
            // переходим на 1-ю вкладку и заполняем поля (для удобства,
            // если что пойдет не так)
            tabs.SelectedIndex = 0;
            txtEmailRealm.Value = txtEmailNewRealm.Value;
            txtEmailWho.Value = txtEmailNewWho.Value;
            txtPassword.Value = txtPasswordNew.Value;
            // выполняем аутентификацию
            authSequence(email, password);
        }

        protected void Page_Load(object sender, EventArgs e) {
            FormsAuthenticationConfiguration fac = new FormsAuthenticationConfiguration();
            fac.Timeout = new TimeSpan(0, Session.Timeout, 0);

            if (Context.User.Identity.IsAuthenticated) {
                Response.Redirect("Dashboard.aspx");
            }
        }
    }
}
